'''
Author: cw
Date: 2025-07-21
Description: ...
'''
from datetime import datetime
from collections import Counter

from fapi import ServiceError

from models.mysql_model import (
    Users, Questions, Sessions
)
from models.data_model import Answer
from modules.image_task_mgr import TaskStatus
from modules import (
    session_mgr,
    question_mgr,
    tests_mgr,
    image_task_mgr,
    task_schedule_wpr
)
from utils import db_util
from utils.wx_util import (
    build_text_response,
    build_image_response
)


async def handle_subscribe(appid: str, openid: str, source_id: str):
    """处理用户关注事件"""
    async with db_util.session_context() as session:
        user = await session.get(Users, openid)
        if not user:
            # 创建新用户
            user = Users(
                appid=appid,
                openid=openid,
                subscribe_time=datetime.now()
            )
            session.add(user)
    # 返回欢迎消息
    reply_content = "👋hi! 欢迎关注💕，回复 “菜单” 有惊喜等着你哟~"
    return build_text_response(openid, source_id, reply_content)


async def handle_menu_click(
    appid: str,
    openid: str,
    event_key: str,
    source_id: str
):
    """处理菜单点击事件"""
    if event_key == "START_QUIZ":
        # 开始测试
        pass
        # return await start_test(appid, openid, source_id)
    return build_text_response(openid, source_id, "功能开发中，敬请期待")


async def menus(appid: str, openid: str, source_id: str):
    """查看菜单列表"""
    menus = {
        "测试": "可进行多项人格测试哦~",
        "云作图": "生成个人专属链接，点击即可作图~",
        "作图 + 描述词": "公众号中直接出片~ 如: 作图 一个可爱的小狗"
    }
    reply_content = "功能菜单：\n"
    for key, value in menus.items():
        reply_content += f'👉 输入 "{key}"  {value}\n'
    return build_text_response(openid, source_id, reply_content)

async def select_tests(appid: str, openid: str, source_id: str):
    """查看测试列表"""
    tests = await tests_mgr.get_list(appid)
    reply_content = '\n'.join([
        f'{i+1}. {test.get("title")}' for i, test in enumerate(tests)
    ])
    reply_content += '\n\n回复 数字编号(1、2、3...) 进入测试'
    return build_text_response(openid, source_id, reply_content)


async def start_test(appid: str, openid: str, source_id: str, index: int):
    """开始测试流程"""
    # 鉴权
    test = await tests_mgr.get_by_appid(appid, offset=int(index) - 1)
    if not test:
        raise ServiceError(msg=f'测试:{index}不存在')

    # 获取第一道问题
    first_question = await question_mgr.build(test.get("id"))
    if not first_question:
        raise ServiceError(msg='暂无题目，请稍后再试')
    # 记录用户当前答题状态 & 处理掉尚未完成的答题记录
    await session_mgr.create(appid, openid, test.get("id"))
    # 实际应用中应使用更完善的状态管理
    return build_text_response(openid, source_id, first_question)


async def handle_user_answer(
    appid: str,
    openid: str,
    content: str,
    source_id: str
):
    """处理用户答案"""
    # 微信只能推送openid,所以只能通过openid 来查询session(latest)
    user_session = await session_mgr.find_latest_session(openid)
    if not user_session:
        raise ServiceError(msg='回复 “菜单” 查看更多有趣节目！')
    offset = len(user_session.content or [])
    question = await question_mgr.get(user_session.test_id, offset)
    if not question:
        raise ServiceError(msg='答题完成，回复 “测试” 查看更多趣味测试！')

    # 解析用户答案
    answer = await parse_answer(question, content)
    if not answer:
        raise ServiceError(msg=f'请输入有效的选项（{question.checked}）')
    # 更新答题记录
    await session_mgr.update_answer(user_session.session_id, answer)
    # 判断是否还有下一题
    next_question = await question_mgr.build(user_session.test_id, (offset + 1))
    if next_question:
        return build_text_response(openid, source_id, next_question)
    else:
        print('答题完成')
        report = await gen_report(user_session)
        await session_mgr.soft_delete(user_session.session_id)
        return build_text_response(openid, source_id, report)


async def parse_answer(question: Questions, content: str):
    """解析用户答案"""
    for item in question.options:
        if item.get('key').upper() == content.upper():
            return Answer(
                question_id=question.id,
                question_title=question.question_title,
                question_group=question.group,
                answer_key=item.get('key').upper(),
                answer_value=item.get('value'),
                answer_score=int(item.get('score') or 0)
            )


async def gen_report(user_session: Sessions):
    """生成报告"""
    if not user_session.content:
        raise ServiceError(msg='暂无答题记录')
    total_score = 0
    group_counter = Counter()
    for item in user_session.content:
        answer = Answer(**item)
        total_score += answer.answer_score or 0
        group_counter.update({answer.question_group: answer.answer_score or 0})
    group_res = '\n    '.join(
        [f"👉{key}: {value} 分" for key, value in group_counter.items()]
    )
    rule = ""
    test_info = await tests_mgr.get(user_session.test_id)
    if test_info:
        rule = test_info.get('rule')
    return "\n\n".join([
        '🤝 你好! 您的得分是:',
        f'    {group_res}',
        rule,
        '🫰回复 “测试” 可查看更多趣味测试!',
        "😍我们会定期更新更多有趣测试，欢迎邀请家人朋友一起参与哦~"
    ])


async def do_image(
    appid: str,
    openid: str,
    content: str,
    source_id: str
):
    """用户作图"""
    prompt = content.split("作图")[-1]
    if not prompt:
        raise ServiceError(msg='请输入正确的指令，例如：作图 一只猫,插画风格')
    res = await task_schedule_wpr.create(prompt, appid, openid)
    if not(res and res.get("task", {})):
        raise ServiceError(msg=f'作图失败，请稍后再试，res={res}')
    work_id = res.get("task", {}).get("id")
    # 记录数据库
    await image_task_mgr.create(appid, openid, prompt, work_id)

    return build_text_response(
        openid,
        source_id,
        "正在为您作图...30秒后输入 “查看” 即可获取图片"
    )


async def get_image(
    appid: str,
    openid: str,
    content: str,
    source_id: str
):
    """查看作图"""
    task = await image_task_mgr.get_latest_task(appid, openid)
    detail = task.get('detail') or {}
    if detail.get('media_id'):
        return build_image_response(
            openid,
            source_id,
            detail.get('media_id')
        )
    if task.get("status") == TaskStatus.FAILED.name:
        return build_text_response(
            openid,
            source_id,
            f"作图失败，请检查描述是否合规合理，或者稍后再试.详情{detail.get('error_msg')}"
        )

    return build_text_response(
        openid,
        source_id,
        "正在努力为你作图，请稍后再来查看！"
    )


async def do_image_by_link(
    appid: str,
    openid: str,
    content: str,
    source_id: str
):
    """用户h5作图"""
    url = f'https://image.jbdhm.icu/user/{openid}'
    return build_text_response(
        openid,
        source_id,
        f"点击在线作图 \n👉{url}"
    )
